#pragma once

#include "Modifies.h"

Modifies::Modifies(VarTable* vt,StmtTable *st,ProcTable* pt) { 
	myST = st;
	myVT = vt;
	myPT = pt;
};

void Modifies::setModifiesStmtModifies(INDEX stmtNo, INDEX varIndex) {
	modifiesTableStmt.insert(std::make_pair<INDEX, INDEX>(stmtNo, varIndex));
}

void Modifies::setModifiesProcModifies(INDEX procIndex, INDEX varIndex) {
	unordered_multimap<INDEX,set<INDEX>>::const_iterator got = modifiesTableProc.find(procIndex);
	if (got == modifiesTableProc.end()) {
		set<INDEX> newSet;
		newSet.insert(varIndex);
		modifiesTableProc.insert(std::make_pair<INDEX, set<INDEX>>(procIndex, newSet));
	} else {
		for (auto it = modifiesTableProc.begin(); it != modifiesTableProc.end(); ++it) 
		{
			if (it->first == procIndex) 
			{
				it->second.insert(varIndex);
			}
		}
	}
};

INDEX_SET Modifies::getModifiedByStmt(INDEX stmtIndex) {
	INDEX_SET returnVal;
	for (auto it = modifiesTableStmt.begin(); it != modifiesTableStmt.end(); ++it) {
		if (it->first == stmtIndex) {
			returnVal.insert(it->second);
		}
	}
	return returnVal;
};

void Modifies::printAllStmt() {
	cout << "Printing Modifies Table (Stmt)" << endl;
	for (auto it = modifiesTableStmt.begin(); it != modifiesTableStmt.end(); ++it) {
		cout << it->first << " : " << it->second << endl;
	}
};

void Modifies::printAllProc() {
	cout << "Printing Modifies Table (Proc)" << endl;
	for (auto it = modifiesTableProc.begin(); it != modifiesTableProc.end(); ++it) {
		//cout << it->first << " : " << it->second << endl;
	}
};

Schema Modifies::getSynSyn(DESIGN_ENTITY de1, NAME de1Name, NAME de2Name)
{
	vector<NAME> attNames;
	attNames.push_back(de1Name);
	attNames.push_back(de2Name);
	Schema x(2,attNames);
	if(de1=="procedure")
	{
		for (auto it = modifiesTableProc.begin(); it != modifiesTableProc.end(); ++it) {
			
			for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2)
			{
				vector<INDEX> vect;
				vect.push_back(it->first);
				vect.push_back(*it2);
				x.insertTuple(vect);
			}
			
		}
	}
	else
	{
		for (auto it = modifiesTableStmt.begin(); it != modifiesTableStmt.end(); ++it) {
			if ((myST->stmtTable.at(it->first) == de1 || de1 == "stmt")) {
				vector<INDEX> vect;
				vect.push_back(it->first);
				vect.push_back(it->second);
				x.insertTuple(vect);
			}
		}
	}
	return x;
};

Schema Modifies::getSynIdent(DESIGN_ENTITY de1, NAME de1Name, string ident)
{
	vector<NAME> attNames;
	attNames.push_back(de1Name);
	Schema x(1,attNames);
	if(de1=="procedure")
	{
		for (auto it = modifiesTableProc.begin(); it != modifiesTableProc.end(); ++it) 
		{
			for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2)
			{
				vector<INDEX> vect;
				if (myVT->getVarName(*it2)==ident)
				{
					vect.push_back(it->first);
					x.insertTuple(vect);
				}
			}
			
		}
	}
	else
	{
		for (auto it = modifiesTableStmt.begin(); it != modifiesTableStmt.end(); ++it) {
		if ((myST->stmtTable.at(it->first) == de1 || de1 == "stmt") && myVT->getVarName(it->second)==ident) {
			vector<INDEX> vect;
			vect.push_back(it->first);
			x.insertTuple(vect);
		}
	}
	}
	return x;
};

Schema Modifies::getSynUnd(DESIGN_ENTITY de1, NAME de1Name)
{
	vector<NAME> attNames;
	attNames.push_back(de1Name);
	Schema x(1,attNames);
	if(de1=="procedure")
	{
		for (auto it = modifiesTableProc.begin(); it != modifiesTableProc.end(); ++it) {
			vector<INDEX> vect;
			vect.push_back(it->first);
			x.insertTuple(vect);
		}
	}
	else
	{
		for (auto it = modifiesTableStmt.begin(); it != modifiesTableStmt.end(); ++it) {
			if ((myST->stmtTable.at(it->first) == de1 || de1 == "stmt")) {
				vector<INDEX> vect;
				vect.push_back(it->first);
				x.insertTuple(vect);
			}
		}
	}
	return x;
};

Schema Modifies::getIntSyn(INDEX para1, NAME de2Name)
{
	vector<NAME> attNames;
	attNames.push_back(de2Name);
	Schema x(1,attNames);
	for (auto it = modifiesTableStmt.begin(); it != modifiesTableStmt.end(); ++it) {
		if (it->first==para1) {
			vector<INDEX> vect;
			vect.push_back(it->second);
			x.insertTuple(vect);
		}
	}
	return x;
};

Schema Modifies::getIntIdent(INDEX para1, string para2)
{
	vector<NAME> attNames;
	attNames.push_back("_");
	Schema x(1,attNames);
	for (auto it = modifiesTableStmt.begin(); it != modifiesTableStmt.end(); ++it) {
		if ((it->first==para1) && (it->second==myVT->getVarIndex(para2))) {
			vector<INDEX> vect;
			vect.push_back(para1);
			x.insertTuple(vect);
		}
	}
	return x;
};

Schema Modifies::getIntUnd(INDEX para1)
{
	vector<NAME> attNames;
	attNames.push_back("_");
	Schema x(1,attNames);
	for (auto it = modifiesTableStmt.begin(); it != modifiesTableStmt.end(); ++it) {
		if (it->first==para1) {
			vector<INDEX> vect;
			vect.push_back(it->second);
			x.insertTuple(vect);
		}
	}
	return x;
};

Schema Modifies::getIdentIdent(string para1, string para2)
{
	int procIndex = myPT->getProcIndex(para1);
	int varIndex = myVT->getVarIndex(para2);
	vector<NAME> attNames;
	attNames.push_back("_");
	Schema x(1,attNames);
	for (auto it = modifiesTableProc.begin(); it != modifiesTableProc.end(); ++it) {
		if ((it->first==procIndex)) 
		{
			for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2)
			{
				if(*it2==myVT->getVarIndex(para2))
				{
					vector<INDEX> vect;
					vect.push_back(procIndex);
					x.insertTuple(vect);
				}
			}
		}
	}
	return x;
};

Schema Modifies::getIdentSyn(string para1, NAME de2Name)
{
	int procIndex = myPT->getProcIndex(para1);
	vector<NAME> attNames;
	attNames.push_back(de2Name);
	Schema x(1,attNames);
	for (auto it = modifiesTableProc.begin(); it != modifiesTableProc.end(); ++it) {
		if ((it->first==procIndex)) 
		{
			for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2)
			{
				vector<INDEX> vect;
				vect.push_back(*it2);
				x.insertTuple(vect);
			}
		}
	}
	return x;
};

Schema Modifies::getIdentUnd(string para1)
{
	int procIndex = myPT->getProcIndex(para1);
	vector<NAME> attNames;
	attNames.push_back("_");
	Schema x(1,attNames);
	for (auto it = modifiesTableProc.begin(); it != modifiesTableProc.end(); ++it) {
		if (it->first==procIndex) 
		{
			for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2)
			{
				vector<INDEX> vect;
				vect.push_back(*it2);
				x.insertTuple(vect);
			}
		}
	}
	return x;
};